package com.woniuxy.woniufp.gateway.filters;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.woniuxy.woniufp.common.model.constant.RedisConstant;
import com.woniuxy.woniufp.common.model.constant.UserConstant;
import com.woniuxy.woniufp.common.model.exceptions.Assert;
import com.woniuxy.woniufp.common.model.result.Result;
import com.woniuxy.woniufp.common.model.result.enums.IErrorCode;
import com.woniuxy.woniufp.common.model.result.enums.impl.BusinessCode;
import com.woniuxy.woniufp.common.model.utils.JwtUtils;
import com.woniuxy.woniufp.gateway.config.IgnorePathConfig;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.concurrent.TimeUnit;


@Configuration
@Slf4j
public class AuthFilter  implements GlobalFilter {

    @Autowired
    IgnorePathConfig ignorePathConfig ;
    @Autowired
    JwtUtils jwtUtils ;

    @Autowired
    StringRedisTemplate stringRedisTemplate ;

    @Override
    @SneakyThrows
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1. 放行不需要认证的资源  /user/login  /user/register  白名单资源
        //  获取request对象  和response对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        // 1.1 、获取这些白名单的资源的路径
        String path = request.getURI().getPath();
        log.info("接收的请求路径:{}",path);
        //获取所有需要放行的资源路径
        PathMatcher pathMatcher = new AntPathMatcher();
        List<String> uris = ignorePathConfig.getUris();
        for (String uri :uris) {
            if (pathMatcher.match(uri,path)) {
                //放行
                return chain.filter(exchange);
            }
        }

        //2 获取请求头中的 token
        String token = request.getHeaders().getFirst("token");
        //2.1 、token 为空
        //Assert.error(token, BusinessCode.TOKEN_ISNULL);
        if (StringUtils.isEmpty(token)) {
            return  errorResponse(response,BusinessCode.TOKEN_ISNULL);
        }
        //2.1 、验证token是否合法
        token = token.replace("Bearer ",""); //去掉token中前缀
        boolean verifyToken = jwtUtils.verifyToken(token);
        if (!verifyToken) {
            return errorResponse(response,BusinessCode.TOKEN_INVALID);
        }

        //获取 token中信息
        String userId = jwtUtils.parseToken(token, UserConstant.TOKEN_USERID)+"";
        String userName = (String) jwtUtils.parseToken(token,UserConstant.TOKEN_USERNAME);
        String phone = (String) jwtUtils.parseToken(token,UserConstant.TOKEN_PHONE);

        //验证是否过期
        /*String redisToken = stringRedisTemplate.opsForValue().get(RedisConstant.USER_TOKEN + userId);
        if (StringUtils.isEmpty(redisToken)) {
            return errorResponse(response,BusinessCode.TOKEN_EXPIRATION);
        }*/
        String key = RedisConstant.USER_TOKEN + userId ;
        if (!stringRedisTemplate.hasKey(key)) {
            return errorResponse(response,BusinessCode.TOKEN_EXPIRATION);
        }

        // token的续期  想session中存储 token 回复30分钟
        stringRedisTemplate.opsForValue().set(RedisConstant.USER_TOKEN + userId,token,30, TimeUnit.MINUTES);

        //重写请求头 把 用户信息 直接写到请求头
        request.mutate().header(UserConstant.TOKEN_USERID,userId);
        request.mutate().header(UserConstant.TOKEN_USERNAME,userName);
        request.mutate().header(UserConstant.TOKEN_PHONE,phone);

        return chain.filter(exchange);
    }

    private static Mono<Void> errorResponse(ServerHttpResponse response, IErrorCode errorCode) throws Exception {
        Result result = Result.fail(errorCode);
        byte[] bytes = new ObjectMapper().writeValueAsBytes(result);
        DataBuffer dataBuffer= response.bufferFactory().wrap(bytes);
        // 返回错误
        return response.writeWith(Mono.just(dataBuffer));
    }

    public static void main(String[] args) {
        PathMatcher pathMatcher = new AntPathMatcher();
        boolean match = pathMatcher.match("/**/user/login", "/user/login");
        boolean match1 = pathMatcher.match("/**/user/register", "/user/register");
        System.out.println(match);
        System.out.println(match1);
    }
}
